package com.jeasonzhao.commons.db.helper;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Hashtable;

public class ConnectionStringInfo
{
    private String id = null;
    private String userId = null;
    private String password = null;
    private java.util.Hashtable<String,String> m_parametersValue = null;
    private String m_strDriverName = null;
    private String m_strDriverClass = null;
    private String m_strConnectionString = null;
    private ArrayList<ConnectionStringKey> m_keys = null;

    public ConnectionStringInfo(String jdbcDriverName,String jdbcDriverClass,String connectionStringTemplate)
    {
        this.m_strDriverClass = jdbcDriverClass == null ? null : jdbcDriverClass.trim();
        this.m_strConnectionString = connectionStringTemplate;
        this.m_strDriverName = null == jdbcDriverName ? null : jdbcDriverName.trim();
        parseKeys();
    }

    private ConnectionStringInfo()
    {

    }

    public String getId()
    {
        return this.id;
    }

    public void setId(String strId)
    {
        this.id = strId;
    }

    public String getUserId()
    {
        return this.userId;
    }

    public void setUserId(String strId)
    {
        this.userId = strId;
    }

    public String getPassword()
    {
        return this.password;
    }

    public void setPassword(String strId)
    {
        this.password = strId;
    }

    public String getParameterValue(String strKey)
    {
        if(null == m_parametersValue || strKey == null || strKey.trim().length() < 1)
        {
            return null;
        }
        strKey = strKey.toLowerCase().trim();
        return m_parametersValue.get(strKey);
    }

    public void addParameterValue(String strKey,String value)
    {
        if(null == strKey || strKey.trim().length() < 1 || value == null)
        {
            return;
        }
        if(null == m_parametersValue)
        {
            m_parametersValue = new Hashtable<String,String>();
        }
        m_parametersValue.put(strKey.trim().toLowerCase(),value);
    }

    public boolean isMatchDriver(String str)
    {
        return null != str &&
            (str.trim().equalsIgnoreCase(this.m_strDriverName)
             || str.trim().equalsIgnoreCase(this.m_strDriverClass)
            );
    }

    public String getDriver()
    {
        return this.m_strDriverClass;
    }

    public String getURL()
    {
        return this.m_strConnectionString;
    }

    public String parseConnectionString(Hashtable<String,String> parameters)
        throws SQLException
    {
        if(null == m_keys || m_keys.size() < 1 || this.m_strConnectionString == null)
        {
            return this.m_strConnectionString;
        }
        String strReturn = this.m_strConnectionString;
        for(ConnectionStringKey kp : m_keys)
        {
            String strName = kp.getName();
            String strValue = null;
            if(null != parameters && parameters.containsKey(strName.trim().toLowerCase()))
            {
                strValue = parameters.get(strName.trim().toLowerCase());
            }
            if(null == strValue)
            {
                strValue = kp.getValue();
            }
            if(null == strValue)
            {
                throw new SQLException("Connection String building failed: Can not get value of parameter:" + strName);
            }
            strReturn = strReturn.replaceAll("%" + kp.getInitKey() + "%",strValue);
        }
        return strReturn;

    }

    public String parseConnectionString(String ...params)
        throws SQLException
    {
        java.util.Hashtable<String,String> aps = new java.util.Hashtable<String,String>();
        for(int n = 0;null != params && n + 1 < params.length;n += 2)
        {
            if(null == params[n])
            {
                continue;
            }
            aps.put(params[n].trim().toLowerCase(),params[n + 1]);
        }
        return parseConnectionString(params == null || params.length == 0 ? this.m_parametersValue : aps);
    }

    public ArrayList<ConnectionStringKey> getKeys()
    {
        return this.m_keys;
    }

    public String getDriverName()
    {
        return this.m_strDriverName;
    }

    private void parseKeys()
    {
        if(null == this.m_strConnectionString)
        {
            return;
        }
        int nprev = -1;
        m_keys = new ArrayList<ConnectionStringKey>();
        while(true)
        {
            int n = this.m_strConnectionString.indexOf("%",nprev);
            if(n < 0)
            {
                break;
            }
            int n2 = this.m_strConnectionString.indexOf("%",n + 1);
            if(n2 < 0)
            {
                break;
            }
            String strSub = this.m_strConnectionString.substring(n + 1,n2);
            ConnectionStringKey key = new ConnectionStringKey();
            key.setInitKey(strSub);
            if(strSub.indexOf(":") > 0)
            {
                int nx = strSub.indexOf(":");
                key.setName(strSub.substring(0,nx));
                key.setValue(strSub.substring(nx + 1));
            }
            else
            {
                key.setName(strSub);
                key.setValue(null);
            }
            m_keys.add(key);
            nprev = n2 + 1;
        }
    }

    public ConnectionStringInfo copyNew()
    {
        ConnectionStringInfo conn = new ConnectionStringInfo();
        conn.id = this.id;
        conn.m_strDriverName = this.m_strDriverName;
        conn.m_strDriverClass = this.m_strDriverClass;
        conn.m_strConnectionString = this.m_strConnectionString;
        conn.userId = this.userId;
        conn.password = this.password;
        if(this.m_parametersValue != null)
        {
            conn.m_parametersValue = new Hashtable<String,String>();
            for(String s : this.m_parametersValue.keySet())
            {
                conn.m_parametersValue.put(s,this.m_parametersValue.get(s));
            }
        }
        if(null != this.m_keys)
        {
            conn.m_keys = new ArrayList<ConnectionStringKey>();
            for(ConnectionStringKey s : this.m_keys)
            {
                ConnectionStringKey k = new ConnectionStringKey();
                k.setInitKey(s.getInitKey());
                k.setName(s.getName());
                k.setValue(s.getValue());
                conn.m_keys.add(k);
            }
        }
        return conn;
    }

    public String toString()
    {
        StringBuffer buf = new StringBuffer();
        if(this.id != null)
        {
            buf.append(" id=" + this.id);
        }
        if(this.m_strDriverName != null)
        {
            buf.append(" dbms=" + this.m_strDriverName);
        }
        if(null != this.m_parametersValue)
        {
            for(String s : this.m_parametersValue.keySet())
            {
                buf.append(" " + s + "=" + m_parametersValue.get(s));
            }
        }
        return buf.toString();
    }

    public Connection getConnection()
        throws SQLException
    {
        String strUrl = this.parseConnectionString();
        return ConnectionHelper.connect(this.m_strDriverClass
                                        ,strUrl
                                        ,this.getUserId()
                                        ,this.getPassword());
    }
}
